#include "ItemType.h"

#include "boost/random/mersenne_twister.hpp"
#include "boost/random/uniform_real.hpp"
#include "boost/random/variate_generator.hpp"
#include <ctime>
boost::mt19937 rng;

ItemType::ItemType(vector< pair< const Effect*, const unsigned long > > effects) : levels(map<unsigned int, LevelAffixes>()) {
	const Effect* effectPtr = NULL;
	unsigned long bitmap = 0;
	unsigned int level = 0;
	for ( vector< pair< const Effect*, const unsigned long > >::iterator i = effects.begin(); i != effects.end(); ++i ) {
		effectPtr = i->first;
		bitmap = i->second;
		for ( SoulgemIterator j = SoulgemIterator(); j <= ultra; ++j ) {
			if ( (bitmap & j) != 0 || effectPtr->hasAffix(j) ) {
				level = getSoulLevel(*j, effectPtr->getRank());
				addToLevel(level, &((*effectPtr)[j]));
			}
		}
	}
}

pair<unsigned int, LevelAffixes*> ItemType::getLevel(unsigned int level) {
	for ( map<unsigned int, LevelAffixes>::reverse_iterator i = levels.rbegin(); i != levels.rend(); --i )
		if ( i->first < level )
			return pair<unsigned int, LevelAffixes*>(i->first, &(i->second));
	return pair<unsigned int, LevelAffixes*>(0, NULL);
}

bool ItemType::addToLevel(unsigned int level, const Affix* affix) {
	pair<map<unsigned int, LevelAffixes>::iterator, bool> i = levels.insert(pair<unsigned int, LevelAffixes>(level, LevelAffixes()));
	if ( i.second )
		i.first->second.previous = getLevel(level-1).second;
	return i.first->second.addAffix(affix);
}

bool ItemType::addToLevel(unsigned int level, vector<const Affix*> affixes) {
	pair<map<unsigned int, LevelAffixes>::iterator, bool> i = levels.insert(pair<unsigned int, LevelAffixes>(level, LevelAffixes()));
	if ( i.second )
		i.first->second.previous = getLevel(level-1).second;
	return i.first->second.addAffixes(affixes);
}

const Affix* ItemType::chooseRandomAffix(unsigned int level, bool calcAllLevelsLtEq) {
	map<double, const Affix*> potentials = map<double, const Affix*>();
	double size = 0;
	for ( LevelAffixes::Iterator i (&levels[level], calcAllLevelsLtEq); !(i.isEnd()); ++i ) {
		potentials.insert(pair<double, const Affix*>(size, *i));
		size += (*i)->getFreq();
	}
	rng.seed(time(NULL));
	boost::uniform_real<double> dist = boost::uniform_real<double>(0,size);
	boost::variate_generator<boost::mt19937, boost::uniform_real<double> >gen(rng, dist);
	double choice = gen();
	for ( map<double, const Affix*>::reverse_iterator i = potentials.rbegin(); i != potentials.rend(); --i )
		if ( i->first <= choice )
			return i->second;
	return potentials[0];
}
